package com.yunfinal.api.service.doc;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.core.Action;
import com.jfinal.core.JFinal;
import com.jfinal.kit.Kv;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.StrKit;
import com.jfinal.template.Engine;
import com.jfinal.template.Template;
import com.jfinal.template.source.ClassPathSource;
import com.yunfinal.api.service.ApiService;
import org.commonmark.Extension;
import org.commonmark.ext.autolink.AutolinkExtension;
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension;
import org.commonmark.ext.gfm.tables.TablesExtension;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 管理和生成文档
 */
public class ApiDocService extends ApiService {
    public static final ApiDocService ME = new ApiDocService();

    public String api_src_path = "/src/main/resources";
    public String api_doc_path = "/webapp/assets/api_doc";
    public String templateName = "/generate/ApiDoc.jf";
    protected Template template;

    /**
     * 获取全部actionKey
     * PS：如果你觉得文档的排序没有规则感，那是由于你命名路径时没有分好路径名
     *
     * @return actionKey 和 doc
     */
    public List<Kv> all(){
        List<String> allActionKeys = JFinal.me().getAllActionKeys();
        List<Kv> ret = new ArrayList<>(allActionKeys.size());
        for (String actionKey : allActionKeys) {
            Kv val = getKvByActionKey(actionKey);
            ret.add(val);
        }
        ret.remove(0);
        return ret;
    }

    protected Kv getKvByActionKey(String actionKey) {
        String[] urlPara = new String[1];
        Action action = JFinal.me().getAction(actionKey, urlPara);
        ApiDoc doc = action.getMethod().getAnnotation(ApiDoc.class);
        Kv val = Kv.by("actionKey", actionKey);
        if (doc != null && isNotBlank(doc.value())) {
            val.set("doc",  doc.value());
        }
        return val;
    }

    public String details(JSONObject kv) {
        String actionKey = kit.get(kv, "actionKey");
        StringBuilder srcPath = new StringBuilder();
        srcPath.append(api_doc_path).append(actionKey).append(".md");
        String fileNameStr = srcPath.toString();
        boolean cover = kv.getBooleanValue("cover");
        if (cover == true){
            //强行覆盖
            fileNameStr = generate(kv, srcPath, fileNameStr);
            return "已覆盖，请用IDEA打开文件进行编辑：".concat(fileNameStr);
        }
        //文件生成或检查
        try {
            return htmlRenderer(fileNameStr);
        }catch (IllegalArgumentException nullE){
            //不存在就创建
            fileNameStr = generate(kv, srcPath, fileNameStr);
            return "请用IDEA打开文件进行编辑：".concat(fileNameStr);
        }
    }

    /**
     * 渲染 MD为 HTML
     * @param fileNameStr
     * @return
     */
    protected String htmlRenderer(String fileNameStr) {
        ClassPathSource classPathSource = new ClassPathSource(fileNameStr);
        String mdStr = classPathSource.getContent().toString();
        List<Extension> extensions = new ArrayList<>();
        extensions.add(TablesExtension.create());
        extensions.add(StrikethroughExtension.create());
        extensions.add(AutolinkExtension.create());
        Node node = Parser.builder().extensions(extensions).build().parse(mdStr);
        String render = HtmlRenderer.builder().extensions(extensions).build().render(node);
        return render;
    }

    /**
     *生成文件
     */
    protected String generate(JSONObject kv, StringBuilder srcPath, String fileNameStr) {
        try {
            srcPath.setLength(0);
            srcPath.append(PathKit.getWebRootPath());
            srcPath.append(api_src_path).append(fileNameStr);
            fileNameStr = srcPath.toString();
            File file = new File(fileNameStr);
            file.getParentFile().mkdirs();
            getTemplate().render(kv, file);
            log.info("DOC文件创建：" + fileNameStr);
        } catch (Exception e) {
            log.error("文件创建失败：异常", e);
        }
        return fileNameStr;
    }

    protected Template getTemplate() {
        if (null == this.template){
            Engine engine = new Engine(ApiDocService.class.getName());
            engine.addSharedMethod(new StrKit());
            engine.setToClassPathSourceFactory();
            this.template = engine.getTemplate(this.templateName);
        }
        return this.template;
    }
}
